package cn.chendd.compress;

import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * JDK中内置的zip压缩和解压缩实现
 *
 * @author chendd
 * @date 2023/3/4 19:50
 */
public class CompressZip {

    /**
     * 压缩文件或文件夹（递归压缩子层）
     * @param file 文件或文件夹
     * @param zipFile zip文件
     * @throws IOException 异常处理
     */
    public static void zip(File file, File zipFile) throws IOException {
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile) , Charset.forName("GBK"))) {
            generareZipFile(file, zos, file);
        }
    }

    /**
     * 压缩文件或文件夹（递归压缩子层）
     * @param file 文件或文件夹
     * @param zipFile zip文件
     * @param charset 编码
     * @param comment 备注
     * @throws IOException 异常处理
     */
    public static void zip(File file, File zipFile , String charset , String comment) throws IOException {
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile) , Charset.forName(charset))) {
            if (StringUtils.isNotEmpty(comment)) {
                zos.setComment(comment);
            }
            generareZipFile(file, zos, file);
        }
    }

    /**
     * 生成zip文件
     * @param inFile 原文件
     * @param zos 压缩流
     * @param rootFile 根文件
     * @throws IOException 异常处理
     */
    private static void generareZipFile(File inFile, ZipOutputStream zos, File rootFile) throws IOException {
        if (inFile.isFile()) {
            putEntryFile(zos, rootFile, inFile);
            return;
        }
        File[] files = inFile.listFiles();
        if (files == null || files.length == 0) {
            putEntryEmptyFolder(zos , inFile , rootFile);
            return;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                generareZipFile(file, zos, rootFile);
            } else {
                putEntryFile(zos, file, rootFile);
            }
        }
    }

    /**
     * 压缩空文件夹
     * @param zos 文件流
     * @param file 文件
     * @param rootFile 根文件
     * @throws IOException 异常处理
     */
    private static void putEntryEmptyFolder(ZipOutputStream zos, File file, File rootFile) throws IOException {
        String path = StringUtils.substringAfter(file.getAbsolutePath(), rootFile.getAbsolutePath() + File.separator);
        ZipEntry zipEntry;
        //处理空文件夹
        String folder = file.isDirectory() ? "/" : StringUtils.EMPTY;
        if (StringUtils.isBlank(path)) {
            zipEntry = new ZipEntry(file.getName() + folder);
        } else {
            zipEntry = new ZipEntry(path + folder);
        }
        zos.putNextEntry(zipEntry);
        zos.closeEntry();
        zos.flush();
    }

    /**
     * 压缩文件
     * @param zos 文件流
     * @param file 文件
     * @param rootFile 根文件
     * @throws IOException 异常处理
     */
    private static void putEntryFile(ZipOutputStream zos, File file, File rootFile) throws IOException {
        String path = StringUtils.substringAfter(file.getAbsolutePath(), rootFile.getAbsolutePath() + File.separator);
        ZipEntry zipEntry;
        if (StringUtils.isBlank(path)) {
            zipEntry = new ZipEntry(file.getName());
        } else {
            zipEntry = new ZipEntry(path);
        }
        zos.putNextEntry(zipEntry);
        Files.copy(file.toPath(), zos);
        zos.closeEntry();
        zos.flush();
    }

}
